package com.kayang.feishu.service;

import com.kayang.common.db.Database;
import com.kayang.common.db.DatabaseFactory;
import com.kayang.feishu.config.FeiShuConfig;
import com.kayang.feishu.pojo.AccessToken;
import com.kayang.feishu.pojo.AppIdentication;
import com.kayang.nadapt.table.DataRow;
import com.kayang.nadapt.table.DataTable;
import com.kayang.nadapt.util.Convert;
import com.kayang.nadapt.util.JsonConvert;
import com.kayang.nadapt.util.LogHelper;
import com.kayang.nadapt.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class AccessTokenService {

    @Autowired
    FeiShuConfig feiShuConfig;

    private Object locker = new Object();
    private  static ConcurrentHashMap<String, AccessToken> accessTokenCache = new ConcurrentHashMap();

    private  static ConcurrentHashMap<String, AppIdentication> appIdenticationCache = new ConcurrentHashMap();

    public AccessToken getAccessToken(String appkey){
        AccessToken accessToken = accessTokenCache.get(appkey);
            if(accessToken == null || accessToken.isExpire()) {
                synchronized (locker) {
                    accessToken = accessTokenCache.get(appkey);
                    if (accessToken == null || accessToken.isExpire()){
                        accessToken = getAccessTokenByAPI(appkey);
                    }
                }
            }
        return accessToken;
    }

    public String getAccessTokenStr(String appkey){
        AccessToken accessToken = getAccessToken( appkey);
        return accessToken.getToken();
    }

    private AccessToken getAccessTokenByAPI( String appkey) {
        AppIdentication curIdentication = appIdenticationCache.get(appkey);
        if(curIdentication == null){
            curIdentication = loadAppIdentication(appkey);
        }
        String appID = curIdentication.getAppId();
        String appSecret = curIdentication.getAppSecret();
        AccessToken accessToken = null;
        String access_token_url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
        Map param = new HashMap();
        param.put("app_id", appID );
        param.put("app_secret", appSecret);

        Map<String, Object> map = httpPost(access_token_url, param);
        if (!map.isEmpty()) {
            try {
                accessToken = new AccessToken();
                accessToken.setToken(Convert.toString(map.get("tenant_access_token")));
                int expires_in = Convert.toInt32(map.get("expire"));
                accessToken.setExpiresAt(LocalDateTime.now().plusSeconds(expires_in / 2));
                accessTokenCache.put(appkey, accessToken);
            } catch (Exception e) {
                accessToken = null;
                LogHelper.error(StringUtil.format("获取token出现异常 appkey:{0}; 响应: errcode:{1} , errmsg:{2}", appkey, map.get("errcode"), map.get("errmsg")), e);
            }
        }
        return accessToken;
    }

    public AppIdentication getAppIdentication(String appkey){
        AppIdentication identication = appIdenticationCache.get(appkey);
        if(identication == null) {
            synchronized (locker) {
                identication = appIdenticationCache.get(appkey);
                if (identication == null){
                    identication = loadAppIdentication(appkey);
                }
            }
        }
        return identication;
    }

    private AppIdentication loadAppIdentication(String appkey){
        Database db = DatabaseFactory.getDatabase();
       long startTime = System.currentTimeMillis();
        DataTable dt = db.queryTable("select * from SkyFeiShuApplication");
        long endtime = System.nanoTime();
        long durtime = endtime - startTime;

        for (DataRow dataRow : dt.getRows()) {
            AppIdentication identication = new AppIdentication();
            identication.setAppkey(dataRow.getString("AppKey"));
            identication.setAppId(dataRow.getString("AppId"));
            identication.setAppSecret(dataRow.getString("AppSecret"));
            identication.setCallbackURL(dataRow.getString("CallBackURL"));
            identication.setModifyDate(dataRow.getDate("ModifyDate"));
            identication.setCreateDate(dataRow.getDate("CreateDate"));
            identication.setRemark(dataRow.getString("remark"));
            appIdenticationCache.put(dataRow.getString("AppKey"), identication);
        }
        return appIdenticationCache.get(appkey);
    }

    private Map httpPost(String request, Map param) {
        Map  ret = new HashMap();
        StringBuffer buffer = new StringBuffer();
        InputStream input = null;
        InputStreamReader inputReader = null;
        BufferedReader reader = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(request);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("charset", "utf-8");

            // 发送请求参数
            try (OutputStream os = connection.getOutputStream()) {
                byte[] data = JsonConvert.serializeObject(param).getBytes(StandardCharsets.UTF_8);
                os.write(data, 0, data.length);
            }

            input = connection.getInputStream();
            inputReader = new InputStreamReader(input, "UTF-8");
            reader = new BufferedReader(inputReader);
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            ret = JsonConvert.deserializeMap(buffer.toString());
            LogHelper.info(StringUtil.format("URL:{0}, METHOD:POST, RET:{1}", request, ret.toString()));
        } catch (Exception e) {
            String errmsg = StringUtil.format("URL:{0}, METHOD:POST", request);
            LogHelper.error(errmsg, e);
        } finally {
            try {
                connection.disconnect();
                reader.close();
                inputReader.close();
                input.close();
            } catch (IOException e) {
                LogHelper.error(e);
            }
        }
        return ret;
    }


}
